package com.ls.aop.security;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class SecurityAspect {
	private Logger logger = LoggerFactory.getLogger(this.getClass());
	@Autowired
	private PermissionService pService;
	
	/**
	 * 切点
	 */
	@Pointcut("@annotation(AdminOnly)" )
	public void adminOnly() {}
	
	/**
	 * 切点
	 */
//	@Pointcut("within(com.ls.aop.service.*Service)" )//当前包下
//	@Pointcut("within(com.ls.aop.service..*Service)" )//当前包及其子包中
//	@Pointcut("within(com.ls.aop.service..*)" )//当前包及其子包中,这里注意“..”,如果是一个“.”,那么代表当前类路径，否则包含当前及其子包
//	@Pointcut("within(com.ls.aop.service..*Service)" )//当前包及其子包中
	@Pointcut("within(com.ls.aop.service.sub.*)" )
	public void withIn() {}
	
//	@Pointcut("execution(* com.ls.aop.service.*Service.*(..))" ) //对类的所有方法
//	@Pointcut("execution(public * com.ls.aop.service..*.*(..))" )//对子包
//	@Pointcut("execution(public String com.ls.aop.service..*.*(..))" ) //对方法返回值设置
//	@Pointcut("execution(public * com.ls.aop.service..*.*())" ) //对方法参数拦截，无参数
//	@Pointcut("execution(public * com.ls.aop.service..*.*(Long))" ) //对只有一个参数是long类型
//	@Pointcut("execution(public * com.ls.aop.service..*.*(Long,..))" ) //对第一个参数是long类型，后面任意
	@Pointcut("execution(public * com.ls.aop.service..*.*(..)) throws java.lang.IllegalAccessException" ) //只拦截抛出特定类型异常的方法
	public void executionPointCut() {}
	
	
//	@Pointcut("this(com.ls.aop.log.Loggable)" ) //实现了Loggable接口的对象拦截,对应接口的方法
	//实现了该接口的类进行拦截，并生成该接口的代理，那么如果在注入时使用具体类，这里使用接口，那么因为生成的动态代理类和具体类不同，所以不能注入，需要使用接口级别
//	@Pointcut("target(com.ls.aop.log.Loggable)" ) //实现了Loggable接口的对象拦截,没有动态代理时，和this一样
	@Pointcut("bean(product*Service)")
	public void thisPointCut() {}
	
	
	@Pointcut("args(String) && within (com.ls.aop.log.*)")//因为拦截所有类，所以不会用
//	@Pointcut("args(String,Long)")//因为拦截所有类，所以不会用
//	@Pointcut("execution(* *..LogService.*())")//因为拦截所有类，所以不会用
	                         //    返回值 + 包名 + 类名 +(中间用点分割) 方法名 +参数
	public void argsPointCut() {}
	
//	@Pointcut("@within(InheritAnnotation)")//定义在类上
//	@Pointcut("@annotation(AdminOnly)")//定义在方法上
	@Pointcut("@args(AdminOnly)")//定义在方法的参数上，方法参数的类包含此annotation
	public void inheritPointCut() {}
	
	
	
	
	
	
	
	
	/**
	 * 切面，在切点的何地执行（前，中，后，或者抛出异常），定义执行内容
	 */
//	@Before("adminOnly()")
	public void check() {
		logger.error("aspect is called ");
		pService.isAllowed();
		
	}

	/**
	 * 切面，在切点的何地执行（前，中，后，或者抛出异常），定义执行内容
	 */
//	@Before("withIn()")
	public void checkWithin() {
		logger.error("####  checkWithin is called #####");
		pService.isAllowed();
		
	}
	
//	@Before("executionPointCut()")
	public void checkExcution() {
		logger.error("####  checkExcution is called #####");
		pService.isAllowed();
	}
	
	
//	@Before("thisPointCut()")
	public void thisAdvice() {
		logger.error("####  thisAdvice is called #####");
		pService.isAllowed();
	}
	
//	@Before("argsPointCut()")
	public void argsAdvice() {
		logger.error("####  argsAdvice is called #####");
		pService.isAllowed();
	}
	
//	@Before("inheritPointCut()")
	public void inheritAdvice() {
		logger.error("####  inheritAdvice is called #####");
		pService.isAllowed();
	}
	
	@Pointcut("within(com.ls.aop.log.*)")
	public void advicePc() {}
	
//	@Before("advicePc()")
	public void adviceTest() {
		logger.info("  $$$ before method ");
	}
	
//	@After("advicePc()")
	public void afterAdviceTest() {
		logger.info("  $$$ after method ");
	}
	
//	@AfterReturning(value="advicePc()",returning="result")
	public void afterretTest(Object result) {
		logger.info("  $$$ after returning  method {}" ,result );
	}
	
//	@AfterThrowing(value="advicePc()")
	public void afterThrowTest() {
		logger.info("  $$$ after Throw  method {}" );
	}
	
	@Around("advicePc()")
	public void aroundTest(ProceedingJoinPoint joinPoint) throws Throwable {
		logger.info("in aroud before method ");
		Object obj;
		try {
			obj = joinPoint.proceed(joinPoint.getArgs());
			logger.info("in aroud get result {}",obj);
		}catch(Throwable e) {
			logger.info("in around exception method ");
			throw e;
		}finally {
			logger.info("in aroud after method ");
		}
	}
	
	//指定参数
	@Pointcut("execution(public * com..LogService.*(String)) && args(productId)")//这里必须指定包的第一个字符，否则报错
	public void testValue1(String productId) {}
	
//	@Before("testValue1(productId)")
	public void beforeArgs(String productId) throws Throwable {
		logger.info("in beforeArgs method with productId {} ",productId);
	}
	
	//指定参数
	@Pointcut("execution(public * com..LogService.*(String))")//这里必须指定包的第一个字符，否则报错
	public void testValue2() {}
	
	@Before("testValue2() && args(productId)")
	public void beforeArgs2(String productId) throws Throwable {
		logger.info("in beforeArgs2 method with productId {} ",productId);
	}
	
}
